/* 
* File:    profile.c
* CVS:     $Id: sprofile.c,v 1.25.2.2 2006/11/08 21:48:10 terpstra Exp $
* Author:  Philip Mucci
*          mucci@cs.utk.edu
* Mods:    Maynard Johnson
*          maynardj@us.ibm.com
* Mods:    <your name here>
*          <your email address>
*/

/* These architectures use Function Descriptors as Function Pointers */

#if (defined(linux) && defined(__ia64__)) || (defined(_AIX)) ||(defined(__powerpc64__))
#define DO_READS (unsigned long)(*(void **)do_reads)
#define DO_FLOPS (unsigned long)(*(void **)do_flops)
#else
#define DO_READS (unsigned long)(do_reads)
#define DO_FLOPS (unsigned long)(do_flops)
#endif

/* This file performs the following test: sprofile */

#include "prof_utils.h"

int main(int argc, char **argv)
{
   int i, num_events, num_tests = 6, mask = 0x1;
   int EventSet = PAPI_NULL;
   unsigned short **buf = (unsigned short **)profbuf;
   unsigned long length, blength;
   int num_buckets;
   PAPI_sprofil_t sprof[3];
   int retval;
   const PAPI_hw_info_t *hw_info;
   const PAPI_exe_info_t *prginfo;
   caddr_t start, end;

   prof_init(argc, argv, &hw_info, &prginfo);

   start = prginfo->address_info.text_start;
   end = prginfo->address_info.text_end;
   if (start > end)
      test_fail(__FILE__, __LINE__, "Profile length < 0!", PAPI_ESBSTR);
   length = end - start;
   prof_print_address("Test case sprofile: POSIX compatible profiling over multiple regions.\n",prginfo);
   blength = prof_size(length, FULL_SCALE, PAPI_PROFIL_BUCKET_16, &num_buckets);
   prof_alloc(3, blength);

   /* First half */
   sprof[0].pr_base = buf[0];
   sprof[0].pr_size = blength;
   sprof[0].pr_off = (caddr_t) DO_FLOPS;
#if defined(linux) && defined(__ia64__)
   if (!TESTS_QUIET)
      fprintf(stderr, "do_flops is at %p %p\n", &do_flops, sprof[0].pr_off);
#endif
   sprof[0].pr_scale = FULL_SCALE;
   /* Second half */
   sprof[1].pr_base = buf[1];
   sprof[1].pr_size = blength;
   sprof[1].pr_off = (caddr_t) DO_READS;
#if defined(linux) && defined(__ia64__)
   if (!TESTS_QUIET)
      fprintf(stderr, "do_reads is at %p %p\n", &do_reads, sprof[1].pr_off);
#endif
   sprof[1].pr_scale = FULL_SCALE;
   /* Overflow bin */
   sprof[2].pr_base = buf[2];
   sprof[2].pr_size = 1;
   sprof[2].pr_off = 0;
   sprof[2].pr_scale = 0x2;

   EventSet = add_test_events(&num_events, &mask);

   values = allocate_test_space(num_tests, num_events);

   if ((retval = PAPI_sprofil(sprof, 3, EventSet, PAPI_TOT_CYC, THRESHOLD,
                              PAPI_PROFIL_POSIX | PAPI_PROFIL_BUCKET_16)) != PAPI_OK)
      test_fail(__FILE__, __LINE__, "PAPI_sprofil", retval);

   if ((retval = PAPI_start(EventSet)) != PAPI_OK)
      test_fail(__FILE__, __LINE__, "PAPI_start", retval);

   do_both(NUM_ITERS);

   if ((retval = PAPI_stop(EventSet, values[1])) != PAPI_OK)
      test_fail(__FILE__, __LINE__, "PAPI_stop", retval);

   /* clear the profile flag before removing the event */
   if ((retval = PAPI_sprofil(sprof, 3, EventSet, PAPI_TOT_CYC, 0,
                              PAPI_PROFIL_POSIX | PAPI_PROFIL_BUCKET_16)) != PAPI_OK)
      test_fail(__FILE__, __LINE__, "PAPI_sprofil", retval);

   remove_test_events(&EventSet, mask);



   if (!TESTS_QUIET) {
      printf("Test case: PAPI_sprofil()\n");
      printf("---------Buffer 1--------\n");
      for (i = 0; i < length / 2; i++) {
         if (buf[0][i])
            printf("0x%lx\t%d\n", DO_FLOPS + 2 * i, buf[0][i]);
      }
      printf("---------Buffer 2--------\n");
      for (i = 0; i < length / 2; i++) {
         if (buf[1][i])
            printf("0x%lx\t%d\n", DO_READS + 2 * i, buf[1][i]);
      }
      printf("-------------------------\n");
      printf("%u samples fell outside the regions.\n", *buf[2]);
   }
   retval = prof_check(2, PAPI_PROFIL_BUCKET_16, num_buckets);

   for (i=0;i<3;i++) {
      free(profbuf[i]);
   }
   if (retval == 0)
      test_fail(__FILE__, __LINE__, "No information in buffers", 1);

   test_pass(__FILE__, values, num_tests);

   exit(1);
}
